// ajax封装
function queryString(obj) {
    var str = ''
    for (var k in obj) {
        str += k + '=' + obj[k] + '&'
    }
    str = str.slice(0, -1)
    return str
}

/* 
    第一步:验证传递进来的数据类型
        => 必须要是一个对象数据类型
        => 如果不是手动抛出异常: throw new Error()
    第二步:
        => 拿到我们传递进来的参数 
        => 对我们的参数要进行一一的验证
    第三步: 验证每一个参数
        => url 
            -> 必须要传递 
            -> 传递进来的url必须是一个字符串
        => method
            -> 你可以不传递
            -> 如果你要传递 必须是get或者是post
        => async
            -> 你可以不传递
            -> 如果你要传递 必须是一个布尔值
        => data
            -> 你可以不传递
            -> 如果要传递可以是一个字符串 
            -> 如果要传递也可以是对象
        => header
            -> 你可以不传递
            -> 如果你要传递 必须传递一个对象
        => dataType
            -> 你可以不传递
            -> 如果你要传递 必须传递string或者是json
        => success
            -> 你可以不传递
            -> 如果你要传递 必须传递一个函数
        => error
            -> 你可以不传递
            -> 如果你要传递 必须传递一个函数
    第四步: 设置默认值
        => 就是在你没有传递参数的时候也能发送请求
    第五步: 处理默认值
        => 有的默认值是需要我加工一下的
    第六步: 发送ajax请求


*/

function ajax(options) {
    // 第一步: 验证传递进来的数据类型
    // 必须要保证我传递进来是一个对象
    // 首先要对我们的options进行验证 如果不是对象就需要从新传递
    if (Object.prototype.toString.call(options) !== '[object Object]') {
        // 为了提醒更加的明显
        // 我们需要手动抛出一个错误
        throw new Error('你传递的不是一个对象,这里需要一个对象数据类型')
    }
    // 代码能执行到这里说明传递进来的一定是一个对象
    // 第二步:
    const { url, method, async, data, headers, dataType, success, error } = options

    // 第三步: 验证每一个参数
    // 验证 url
    if (!url || typeof url !== 'string') {
        // 手动抛出异常
        throw new Error('url必须要传递而且是一个字符串数据类型')
    }
    // 验证 method
    if (!(method === undefined || /^(get|post)$/i.test(method))) {
        // 手动抛出异常
        throw new Error('请求方式必须是get或者是post你传递的不对')
    }
    // 验证 async
    if (!(async === undefined || typeof async === 'boolean')) {
        // 手动抛出异常
        throw new Error('你传递的不是一个布尔值,这里需要一个布尔值')
    }
    // 验证 data
    if (!(data === undefined || typeof data === 'string' || Object.prototype.toString.call(data) === '[object Object]')) {
        // 手动抛出异常
        throw new Error('你传递的数据不符合我们的要求,必须是字符串或者是对象')
    }
    // 验证 data
    if (!(data === undefined || typeof data === 'string' || Object.prototype.toString.call(data) === '[object Object]')) {
        // 手动抛出异常
        throw new Error('你传递的数据不符合我们的要求,必须是字符串或者是对象')
    }
    // 验证 headers
    if (!(headers === undefined || Object.prototype.toString.call(headers) === '[object Object]')) {
        // 手动抛出异常
        throw new Error('你传递的数据不符合我们的要求,必须是一个对象数据类型')
    }
    // 验证 dataType 
    if (!(dataType === undefined || /^(string|json)$/i.test(dataType))) {
        // 手动抛出异常
        throw new Error('传递的数据类不对 必须是字符串或者是json')
    }
    // 验证 success 
    if (!(success === undefined || typeof success === 'function')) {
        // 手动抛出异常
        throw new Error('传递的数据类不对 必须是一个函数')
    }
    // 验证 error 
    if (!(error === undefined || typeof error === 'function')) {
        // 手动抛出异常
        throw new Error('传递的数据类不对 必须是一个函数')
    }

    // 第四步: 设置默认值
    let _default = {
        // url : 必须要传递 没有url不知道请求发送到哪里
        url: url,
        // method: 如果你传递了就使用你的 没有传递就默认发送get请求
        method: method || 'get',
        // async
        async: typeof async === 'boolean' ? async : true,
        // async: async ?? true // ?? 空值运算
        // data
        data: data || '',
        // headers
        headers: { 'content-type': 'application/x-www-form-urlencoded', ...headers },
        // dataType
        dataType: dataType || 'string',
        // success
        success: success || function () { },
        // error
        error: error || function () { }
    }

    // 第五步: 默认值处理
    if (typeof data === 'object') {
        _default.data = queryString(data)
    }
    // 如果是get请求并且携带了参数
    if (/^get$/i.test(_default.method) && data) {
        _default.url = _default.url + '?' + _default.data
    }

    // 第六步:发送ajax请求
    const xhr = new XMLHttpRequest()

    xhr.open(_default.method, _default.url, _default.async)

    xhr.onload = function () {
        let res = xhr.responseText
        // 根据传递进来的dataType来判断是不是需要解析
        if (_default.dataType === 'json') {
            res = JSON.parse(xhr.responseText)
            // 使用try catch 语法
            // 因为这个语法可以吸收错误
            try {
                _default.success(res)
            } catch (err) {
                _default.error(err)
            }

        } else {
            _default.success(res)
        }
    }

    // 设置请求头
    for (let k in _default.headers) {
        xhr.setRequestHeader(k, _default.headers[k])
    }

    // 这里需要考虑一个问题
    // 发送的请求是get还是post
    // 如果是get请求 直接发送
    // 如果是post请求而且有参数 我们要做处理
    if (/^get$/i.test(_default.method)) {
        xhr.send()
    } else {
        xhr.send(_default.data)
    }
}